package org.example.ipersistent.executor;

import org.example.ipersistent.pojo.Configuration;
import org.example.ipersistent.pojo.MappedStatement;
import org.example.ipersistent.utils.BoundSql;

import javax.sql.DataSource;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SimpleExecutor implements Executor {
  private Connection connection;
  private PreparedStatement preparedStatement;
  private ResultSet resultSet;

  @Override
  public List query(Configuration configuration, MappedStatement mappedStatement, Object param) {
    try {
      DataSource dataSource = configuration.getDataSource();
      connection = dataSource.getConnection();
      BoundSql boundSql = this.getBoundSql(mappedStatement.getSql());
      preparedStatement = connection.prepareStatement(boundSql.getFinalSql());
      Map<Integer, String> prepareMapping = boundSql.getPrepareMapping();
      if (!prepareMapping.isEmpty()) {
        Class<?> paramClass = Class.forName(mappedStatement.getParamType());
        for (Integer key : prepareMapping.keySet()) {
          Field field = paramClass.getDeclaredField(prepareMapping.get(key));
          field.setAccessible(true);
          if (param == null) {
            break;
          }
          Object value = field.get(param);
          preparedStatement.setObject(key + 1, value);
        }
      }
      resultSet = preparedStatement.executeQuery();
      Class<?> resultClass = Class.forName(mappedStatement.getResultType());
      List result = new ArrayList<>();
      while (resultSet.next()) {
        Object o = resultClass.getConstructor().newInstance();
        ResultSetMetaData metaData = resultSet.getMetaData();
        for (int i = 0; i < metaData.getColumnCount(); i++) {
          String columnName = metaData.getColumnName(i + 1);
          Object value = resultSet.getObject(columnName);
          PropertyDescriptor descriptor = new PropertyDescriptor(this.underlineToHump(columnName), resultClass);
          descriptor.getWriteMethod().invoke(o, value);
        }
        result.add(o);
      }
      return result;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public void close() {
    // 释放资源
    if (resultSet != null) {
      try {
        resultSet.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    if (preparedStatement != null) {
      try {
        preparedStatement.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
    if (connection != null) {
      try {
        connection.close();
      } catch (SQLException e) {
        e.printStackTrace();
      }
    }
  }

  private BoundSql getBoundSql(String origin) {
    ArrayList<Integer> start = new ArrayList<>();
    ArrayList<Integer> end = new ArrayList<>();
    int i = 0;
    while ((i = origin.indexOf("#{", i + 1)) != -1) {
      start.add(i);
    }
    i = 0;
    while ((i = origin.indexOf("}", i + 1)) != -1) {
      end.add(i);
    }
    HashMap<Integer, String> map = new HashMap<>();
    HashMap<Integer, String> finalMap = new HashMap<>();
    for (int j = 0; j < start.size(); j++) {
      map.put(j, origin.substring(start.get(j), end.get(j) + 1));
      finalMap.put(j, this.underlineToHump(origin.substring(start.get(j) + 2, end.get(j))));

    }
    for (Integer index : map.keySet()) {
      origin = origin.replace(map.get(index), "?");
    }
    BoundSql boundSql = new BoundSql();
    boundSql.setFinalSql(origin);
    boundSql.setPrepareMapping(finalMap);
    return boundSql;
  }

  private String underlineToHump(String str) {
    //正则匹配下划线及后一个字符，删除下划线并将匹配的字符转成大写
    Matcher matcher = Pattern.compile("_([a-z])").matcher(str);
    StringBuffer sb = new StringBuffer(str);
    if (matcher.find()) {
      sb = new StringBuffer();
      //将当前匹配的子串替换成指定字符串，并且将替换后的子串及之前到上次匹配的子串之后的字符串添加到StringBuffer对象中
      //正则之前的字符和被替换的字符
      matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
      //把之后的字符串也添加到StringBuffer对象中
      matcher.appendTail(sb);
    } else {
      //去除除字母之外的前面带的下划线
      return sb.toString().replaceAll("_", "");
    }
    return underlineToHump(sb.toString());
  }

  private String humpToUnderline(String str) {
    StringBuilder buf = new StringBuilder();
    for (int i = 0; i < str.length(); ++i) {
      char ch = str.charAt(i);
      if (ch >= 'A' && ch <= 'Z') {
        char ch_ucase = (char) (ch + 32);
        if (i > 0) {
          buf.append('_');
        }
        buf.append(ch_ucase);
      } else {
        buf.append(ch);
      }
    }
    return buf.toString();
  }
}
